home *** CD-ROM | disk | FTP | other *** search
- ;;; CMPINLINE Open coding optimizer.
- ;;;
- ;; (c) Copyright Taiichi Yuasa and Masami Hagiya, 1984. All rights reserved.
- ;; Copying of this file is authorized to users who have executed the true and
- ;; proper "License Agreement for Kyoto Common LISP" with SIGLISP.
-
- (in-package 'compiler)
-
- ;;; Pass 1 generates the internal form
- ;;; ( id info-object . rest )
- ;;; for each form encountered.
-
- (defstruct info
- (changed-vars nil) ;;; List of var-objects changed by the form.
- (referred-vars nil) ;;; List of var-objects referred in the form.
- (type t) ;;; Type of the form.
- (sp-change nil) ;;; Whether execution of the form may change
- ;;; the value of a special variable *VS*.
- )
-
- (defvar *info* (make-info))
-
- (defun add-info (to-info from-info)
- (setf (info-changed-vars to-info)
- (append (info-changed-vars from-info)
- (info-changed-vars to-info)))
- (setf (info-referred-vars to-info)
- (append (info-referred-vars from-info)
- (info-referred-vars to-info)))
- (when (info-sp-change from-info)
- (setf (info-sp-change to-info) t))
- )
-
- (defun args-info-changed-vars (var forms)
- (case (var-kind var)
- ((LEXICAL FIXNUM CHARACTER LONG-FLOAT SHORT-FLOAT OBJECT)
- (dolist** (form forms)
- (when (member var (info-changed-vars (cadr form)))
- (return-from args-info-changed-vars t))))
- (REPLACED nil)
- (t (dolist** (form forms nil)
- (when (or (member var (info-changed-vars (cadr form)))
- (info-sp-change (cadr form)))
- (return-from args-info-changed-vars t)))))
- )
-
- (defun args-info-referred-vars (var forms)
- (case (var-kind var)
- ((LEXICAL REPLACED FIXNUM CHARACTER LONG-FLOAT SHORT-FLOAT OBJECT)
- (dolist** (form forms nil)
- (when (member var (info-referred-vars (cadr form)))
- (return-from args-info-referred-vars t))))
- (t (dolist** (form forms nil)
- (when (or (member var (info-referred-vars (cadr form)))
- (info-sp-change (cadr form)))
- (return-from args-info-referred-vars t))))
- ))
-
- ;;; Valid property names for open coded functions are:
- ;;; INLINE
- ;;; INLINE-SAFE safe-compile only
- ;;; INLINE-UNSAFE non-safe-compile only
- ;;;
- ;;; Each property is a list of 'inline-info's, where each inline-info is:
- ;;; ( types { type | boolean } side-effect new-object { string | function } ).
- ;;;
- ;;; For each open-codable function, open coding will occur only if there exits
- ;;; an appropriate property with the argument types equal to 'types' and with
- ;;; the return-type equal to 'type'. The third element
- ;;; is T if and only if side effects may occur by the call of the function.
- ;;; Even if *VALUE-TO-GO* is TRASH, open code for such a function with side
- ;;; effects must be included in the compiled code.
- ;;; The forth element is T if and only if the result value is a new Lisp
- ;;; object, i.e., it must be explicitly protected against GBC.
-
- (defvar *inline-functions* nil)
- (defvar *inline-blocks* 0)
- ;;; *inline-functions* holds:
- ;;; (...( function-name . inline-info )...)
- ;;;
- ;;; *inline-blocks* holds the number of temporary cvars used to save
- ;;; intermediate results during evaluation of inlined function calls.
- ;;; This variable is used to close up blocks introduced to declare static
- ;;; c variables.
-
- (defun inline-args (forms types &aux (locs nil) ii)
- (do ((forms forms (cdr forms))
- (types types (cdr types)))
- ((endp forms) (reverse locs))
- (declare (object forms types))
- (let ((form (car forms))
- (type (car types)))
- (declare (object form type))
- (case (car form)
- (LOCATION (push (coerce-loc (caddr form) type) locs))
- (VAR
- (cond ((args-info-changed-vars (caaddr form) (cdr forms))
- (cond ((and (member (var-kind (caaddr form))
- '(FIXNUM CHARACTER LONG-FLOAT
- SHORT-FLOAT))
- (eq type (var-kind (caaddr form))))
- (let ((cvar (next-cvar)))
- (wt-nl "{" (rep-type type) "V" cvar "= V"
- (var-loc (caaddr form)) ";")
- (push (list 'cvar cvar) locs)
- (incf *inline-blocks*)))
- ((eq (var-kind (caaddr form)) 'OBJECT)
- (let ((cvar (next-cvar)))
- (wt-nl "{object V" cvar "= V"
- (var-loc (caaddr form)) ";")
- (push (coerce-loc (list 'cvar cvar) type) locs)
- (incf *inline-blocks*)))
- (t
- (let ((temp (list 'VS (vs-push))))
- (wt-nl temp "= ")
- (wt-var (caaddr form) (cadr (caddr form)))
- (wt ";")
- (push (coerce-loc temp type) locs)))))
- ((and (member (var-kind (caaddr form))
- '(FIXNUM LONG-FLOAT SHORT-FLOAT))
- (not (eq type (var-kind (caaddr form)))))
- (let ((temp (list 'VS (vs-push))))
- (wt-nl temp "= ")
- (wt-var (caaddr form) (cadr (caddr form)))
- (wt ";")
- (push (coerce-loc temp type) locs)))
- (t (push (coerce-loc (cons 'VAR (caddr form)) type)
- locs))))
- (CALL-GLOBAL
- (if (let ((fname (caddr form)))
- (declare (object fname))
- (and (inline-possible fname)
- (setq ii (get-inline-info
- fname (cadddr form)
- (info-type (cadr form))))))
- (let ((loc (get-inline-loc ii (cadddr form))))
- (cond
- ((or (cadddr ii) ; returns new object
- (and (member (cadr ii)
- '(FIXNUM LONG-FLOAT SHORT-FLOAT))
- (not (eq type (cadr ii)))))
- (let ((temp (list 'VS (vs-push))))
- (wt-nl temp "= " loc ";")
- (push (coerce-loc temp type) locs)))
- ((or (need-to-protect (cdr forms) (cdr types))
- (and (caddr ii) ; side-effectp
- (not (null (cdr forms)))))
- (let ((cvar (next-cvar)))
- (wt-nl "{" (rep-type type) "V" cvar "= ")
- (case type
- (fixnum (wt-fixnum-loc loc))
- (character (wt-character-loc loc))
- (long-float (wt-long-float-loc loc))
- (short-float (wt-short-float-loc loc))
- (otherwise (wt-loc loc)))
- (wt ";")
- (push (list 'cvar cvar) locs)
- (incf *inline-blocks*))
- )
- (t (push (coerce-loc loc type) locs))))
- (let ((temp (list 'VS (vs-push))))
- (let ((*value-to-go* temp)) (c2expr* form))
- (push (coerce-loc temp type) locs))))
- (structure-ref
- (push (coerce-loc (list 'structure-ref
- (car (inline-args (list (caddr form))
- '(t)))
- (cadddr form)
- (car (cddddr form)))
- type)
- locs))
- (SETQ
- (let ((vref (caddr form))
- (form1 (cadddr form)))
- (let ((*value-to-go* (cons 'var vref))) (c2expr* form1))
- (cond ((eq (car form1) 'LOCATION)
- (push (coerce-loc (caddr form1) type) locs))
- (t (setq forms (list* form
- (list 'VAR (cadr form) vref)
- (cdr forms)))
- (setq types (list* type type types))))))
- (t (let ((temp (list 'VS (vs-push))))
- (let ((*value-to-go* temp)) (c2expr* form))
- (push (coerce-loc temp type) locs))))))
- )
-
- (defun coerce-loc (loc type)
- (case type
- (fixnum (list 'FIXNUM-LOC loc))
- (character (list 'CHARACTER-LOC loc))
- (long-float (list 'LONG-FLOAT-LOC loc))
- (short-float (list 'SHORT-FLOAT-LOC loc))
- (t loc)))
-
- (defun get-inline-loc (ii args &aux (locs (inline-args args (car ii)))
- (fun (car (cddddr ii))))
- ;;; Those functions that use GET-INLINE-LOC must rebind the variable *VS*.
- (when (and (stringp fun) (char= (char (the string fun) 0) #\@))
- (let ((i 1) (saves nil))
- (declare (fixnum i))
- (do ((char (char (the string fun) i)
- (char (the string fun) i)))
- ((char= char #\;) (incf i))
- (declare (character char))
- (push (the fixnum (- (char-code char) #.(char-code #\0))) saves)
- (incf i))
- (do ((l locs (cdr l))
- (n 0 (1+ n))
- (locs1 nil))
- ((endp l) (setq locs (reverse locs1)))
- (declare (fixnum n) (object l))
- (if (member n saves)
- (let* ((loc1 (car l)) (loc loc1) (coersion nil))
- (declare (object loc loc1))
- (when (and (consp loc1)
- (member (car loc1)
- '(FIXNUM-LOC CHARACTER-LOC
- LONG-FLOAT-LOC SHORT-FLOAT-LOC)))
- (setq coersion (car loc1))
- (setq loc (cadr loc1)) ; remove coersion
- )
- (cond
- ((and (consp loc)
- (and (member (car loc)
- '(INLINE INLINE-COND INLINE-FIXNUM
- INLINE-CHARACTER INLINE-LONG-FLOAT
- INLINE-SHORT-FLOAT))
- (cadr loc) ;; side-effect-p
- ))
- (wt-nl "{")
- (incf *inline-blocks*)
- (let ((cvar (next-cvar)))
- (push (list 'CVAR cvar) locs1)
- (case coersion
- ((nil) (wt "object V" cvar "= ") (wt-loc loc1))
- (FIXNUM-LOC (wt "int V" cvar "= ") (wt-fixnum-loc loc))
- (CHARACTER-LOC
- (wt "unsigned char V" cvar "= ") (wt-character-loc loc))
- (LONG-FLOAT-LOC
- (wt "double V" cvar "= ") (wt-long-float-loc loc))
- (SHORT-FLOAT-LOC
- (wt "float V" cvar "= ") (wt-short-float-loc loc))
- (t (baboon))))
- (wt ";")
- )
- (t (push loc1 locs1))))
- (push (car l) locs1)))))
- (list (case (cadr ii)
- (boolean 'INLINE-COND)
- (fixnum 'INLINE-FIXNUM)
- (character 'INLINE-CHARACTER)
- (long-float 'INLINE-LONG-FLOAT)
- (short-float 'INLINE-SHORT-FLOAT)
- (otherwise 'INLINE))
- (caddr ii)
- fun
- locs)
- )
-
- (defun get-inline-info (fname args return-type &aux x ii)
- (setq args (mapcar #'(lambda (form) (info-type (cadr form))) args))
- (when (and (setq x (assoc fname *inline-functions*))
- (setq ii (inline-type-matches (cdr x) args return-type)))
- (return-from get-inline-info ii))
- (when (if *safe-compile*
- (setq x (get fname 'inline-safe))
- (setq x (get fname 'inline-unsafe)))
- (dolist** (y x nil)
- (when (setq ii (inline-type-matches y args return-type))
- (return-from get-inline-info ii))))
- (when (setq x (get fname 'inline-always))
- (dolist** (y x)
- (when (setq ii (inline-type-matches y args return-type))
- (return-from get-inline-info ii))))
- nil
- )
-
- (defun inline-type-matches (inline-info arg-types return-type
- &aux (rts nil))
- (if (and (let ((types (car inline-info)))
- (declare (object types))
- (dolist** (arg-type arg-types (endp types))
- (when (endp types) (return nil))
- (cond ((eq (car types) 'fixnum-float)
- (cond ((type>= 'fixnum arg-type)
- (push 'fixnum rts))
- ((type>= 'long-float arg-type)
- (push 'long-float rts))
- ((type>= 'short-float arg-type)
- (push 'short-float rts))
- (t (return nil))))
- ((type>= (car types) arg-type)
- (push (car types) rts))
- (t (return nil)))
- (pop types)))
- (or (eq (cadr inline-info) 'boolean)
- (type>= (cadr inline-info) return-type)))
- (cons (reverse rts) (cdr inline-info))
- nil)
- )
-
- (defun need-to-protect (forms types &aux ii)
- (do ((forms forms (cdr forms))
- (types types (cdr types)))
- ((endp forms) nil)
- (declare (object forms types))
- (let ((form (car forms)))
- (declare (object form))
- (case (car form)
- (LOCATION)
- (VAR
- (when (or (args-info-changed-vars (caaddr form) (cdr forms))
- (and (member (var-kind (caaddr form))
- '(FIXNUM LONG-FLOAT SHORT-FLOAT))
- (not (eq (car types)
- (var-kind (caaddr form))))))
- (return t)))
- (CALL-GLOBAL
- (let ((fname (caddr form)))
- (declare (object fname))
- (when
- (or (not (inline-possible fname))
- (null (setq ii (get-inline-info
- fname (cadddr form)
- (info-type (cadr form)))))
- (caddr ii)
- (cadddr ii)
- (and (member (cadr ii)
- '(fixnum long-float short-float))
- (not (eq (car types) (cadr ii))))
- (need-to-protect (cadddr form) (car ii)))
- (return t))))
- (structure-ref
- (when (need-to-protect (list (caddr form)) '(t))
- (return t)))
- (t (return t)))))
- )
-
- (defun close-inline-blocks ()
- (dotimes** (i *inline-blocks*) (wt "}")))
-
- (si:putprop 'inline 'wt-inline 'wt-loc)
- (si:putprop 'inline-cond 'wt-inline-cond 'wt-loc)
- (si:putprop 'inline-fixnum 'wt-inline-fixnum 'wt-loc)
- (si:putprop 'inline-character 'wt-inline-character 'wt-loc)
- (si:putprop 'inline-long-float 'wt-inline-long-float 'wt-loc)
- (si:putprop 'inline-short-float 'wt-inline-short-float 'wt-loc)
-
- (defun wt-inline-loc (fun locs &aux (i 0))
- (declare (fixnum i))
- (cond ((stringp fun)
- (when (char= (char (the string fun) 0) #\@)
- (setq i 1)
- (do ()
- ((char= (char (the string fun) i) #\;) (incf i))
- (incf i)))
- (do ((size (length (the string fun))))
- ((>= i size))
- (declare (fixnum size))
- (let ((char (char (the string fun) i)))
- (declare (character char))
- (cond ((char= char #\#)
- (wt-loc
- (nth (the fixnum
- (- (char-code (char (the string fun)
- (the fixnum (1+ i))))
- #.(char-code #\0)))
- locs))
- (incf i 2))
- (t
- (princ char *compiler-output1*)
- (incf i)))))
- )
- (t (apply fun locs))))
-
- (defun wt-inline (side-effectp fun locs)
- (declare (ignore side-effectp))
- (wt-inline-loc fun locs))
-
- (defun wt-inline-cond (side-effectp fun locs)
- (declare (ignore side-effectp))
- (wt "(") (wt-inline-loc fun locs) (wt "?Ct:Cnil)"))
-
- (defun wt-inline-fixnum (side-effectp fun locs)
- (declare (ignore side-effectp))
- (when (zerop *space*) (wt "CMP"))
- (wt "make_fixnum(") (wt-inline-loc fun locs) (wt ")"))
-
- (defun wt-inline-character (side-effectp fun locs)
- (declare (ignore side-effectp))
- (wt "code_char(") (wt-inline-loc fun locs) (wt ")"))
-
- (defun wt-inline-long-float (side-effectp fun locs)
- (declare (ignore side-effectp))
- (wt "make_longfloat(") (wt-inline-loc fun locs) (wt ")"))
-
- (defun wt-inline-short-float (side-effectp fun locs)
- (declare (ignore side-effectp))
- (wt "make_shortfloat(") (wt-inline-loc fun locs) (wt ")"))
-
- (defun args-cause-side-effect (forms &aux ii)
- (dolist** (form forms nil)
- (case (car form)
- ((LOCATION VAR structure-ref))
- (CALL-GLOBAL
- (let ((fname (caddr form)))
- (declare (object fname))
- (unless (and (inline-possible fname)
- (setq ii (get-inline-info
- fname (cadddr form)
- (info-type (cadr form))))
- (not (caddr ii)) ; no side-effectp
- )
- (return t))))
- (otherwise (return t)))))
-
- ;;; Borrowed from CMPOPT.LSP
-
- (defun list-inline (&rest x)
- (wt "list(" (length x)) (dolist (loc x) (wt #\, loc)) (wt #\)))
-
- (defun list*-inline (&rest x)
- (case (length x)
- (1 (wt (car x)))
- (2 (wt "make_cons(" (car x) "," (cadr x) ")"))
- (otherwise
- (wt "listA(" (length x)) (dolist (loc x) (wt #\, loc)) (wt #\)))))
-
- ;;; Borrowed from LFUN_LIST.LSP
-
- (defun defsysfun (fname cname-string arg-types return-type
- never-change-special-var-p predicate)
- ;;; The value NIL for each parameter except for fname means "not known".
- (when cname-string (si:putprop fname cname-string 'Lfun))
- (when arg-types
- (si:putprop fname (mapcar 'type-filter arg-types) 'arg-types))
- (when return-type (si:putprop fname (type-filter return-type) 'return-type))
- (when never-change-special-var-p (si:putprop fname t 'no-sp-change))
- (when predicate (si:putprop fname t 'predicate))
- )
-
-